﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using PipeTest.Win32;

namespace PipeTest.Game
{
    public class PipeClient
    {
        public const int FileAttributeNormal = 0x00000080;

        public const int GenericWrite = 0x40000000;

        public const int NmpwaitUseDefaultWait = 0x00000000;

        public SafeFileHandle MPipe;

        public string MPipeName;

        public PipeClient(string pipeName)
        {
            MPipeName = pipeName;
        }

        ~PipeClient()
        {
            Disconnect();
        }

        public static bool IsServerAvailable(string pipeName)
        {
            return NativeMethod.WaitNamedPipe(pipeName, NmpwaitUseDefaultWait) > 0;
        }

        public bool IsServerAvailable()
        {
            return IsServerAvailable(MPipeName);
        }

        public bool Connect()
        {
            MPipe = NativeMethod.CreateFile(MPipeName, GenericWrite, 0, GetSecAttrs(FileShare.None), FileMode.Open, FileAttributeNormal, IntPtr.Zero);
            return !MPipe.IsInvalid;
        }

        public unsafe bool Write(KeyEvent keyEvent)
        {
            int numBytesWritten;
            int result = NativeMethod.WriteFile(MPipe, (byte*)&keyEvent, sizeof(KeyEvent), out numBytesWritten, IntPtr.Zero);
            return result > 0 && numBytesWritten == sizeof (KeyEvent);
        }

        public void Disconnect()
        {
            if (!MPipe.IsInvalid)
            {
                MPipe.Close();
            }
        }

        private static SecurityAttributes GetSecAttrs(FileShare share)
        {
            SecurityAttributes structure = null;
            if ((share & FileShare.Inheritable) != FileShare.None)
            {
                structure = new SecurityAttributes();
                structure.NLength = Marshal.SizeOf(structure);
                structure.BInheritHandle = 1;
            }
            return structure;
        }

        public void WriteKey(int key)
        {
            KeyEvent keyEvent = new KeyEvent();
            keyEvent.DwOfs = NativeMethod.MapVirtualKey(key, 0);
            keyEvent.DwData = 0x80;
            Write(keyEvent);
            Thread.Sleep(50);
            keyEvent.DwData = 0;
            Write(keyEvent);
            Thread.Sleep(50);
        }
    }
}